(*Moteur 3D affichant un fichier ".obj" passé en paramètre *)

(*Variables*)
let dim = ref (1000, 1000)
let fos = float_of_string
let ios = int_of_string
let foi = float_of_int
let iof = int_of_float
let split = Str.split(Str.regexp_string " ")
let strip = ref false
let triangles = ref true
let fkey = ref false
let ekey = ref false

(*Lecture de l'OBJ*)
let rec read vl fl ch =
  match try Some(split (input_line ch)) with _ -> None with
    | None -> vl, fl
    | Some["v";x;y;z] -> read ((fos x, fos y, fos z) :: vl) fl ch
    | Some["f";i;j;k] -> read vl ((fos i, fos j, fos k) :: fl) ch
    | Some s -> read vl fl ch

let vfl fl vl =
  let max = Array.length(fl) in
  let rec t result fl vl x = match x with
    | x when (x>max-1) -> result
    | x -> let (a,b,c) = fl.(x) in
        t ((vl.((iof a)-1),vl.((iof b)-1),vl.((iof c)-1))::result) fl
	  vl (x+1)
  in t [] fl vl 0

let load_obj () =
  let vertices, faces =
    let ch = open_in Sys.argv.(1) in
    let vl, fl = read [] [] ch in
      close_in ch;
    Printf.printf "%d vertices, %d triangles\n%!" (List.length vl) (List.length fl);
      Array.of_list (List.rev vl), Array.of_list (List.rev fl) 
  in let result2 = vfl faces vertices in
    Array.of_list (List.rev result2)

let ech = 10.

(*Affichage*)

let display result3 ()  =
  GlClear.clear [`color; `depth];
  Gl.enable `depth_test;
 
  if(!strip) then GlDraw.begins `line_strip;
  if(!triangles) then GlDraw.begins `triangles;

(*Affichage 3D*)
let l = Array.length(result3) in
let ((aa,bb,cc),(dd,ee,ff),(gg,hh,ii)) = result3.(l-1) in
let middle = aa/.ech/.2. in
	  for i = 0 to l-1 do
	    let ((a,b,c),(d,e,f),(g,h,i)) = result3.(i) in
              GlDraw.vertex3(a/.ech-.middle,b/.ech-.middle,c/.ech-.middle);
	      GlDraw.vertex3(d/.ech-.middle,e/.ech-.middle,f/.ech-.middle);
	      GlDraw.vertex3(g/.ech-.middle,h/.ech-.middle,i/.ech-.middle);
	  done;
	  GlDraw.ends ();

    Gl.disable `depth_test;
    Gl.flush ()

(*Changement d'affichage*)
let idle () =
  GlDraw.color (0.4,0.9,0.2);
  if(!fkey) then
    begin
      if((!strip)&&(!fkey)) 
      then 
	begin 
	  strip:= false; 
	  triangles:=true;
	  Glut.postRedisplay (); 
	  fkey:=false; 
	end
      else
	begin 
	  strip:= true; 
	  triangles:=false;
	  Glut.postRedisplay (); 
	  fkey:=false; 
	end
    end

(*Propriétés de l'affichage*)
let reshape ~w ~h =
  let w = max 1 w and h = max 1 h in
    dim := (w, h);
    GlClear.clear [`color; `depth];
    GlMat.mode `projection;
    GlMat.load_identity ();
    GluMat.perspective ~fovy:45.0 ~aspect:(1.0 *. float w /. float h)
      ~z:(0.1,1000.0);
    begin
      GluMat.look_at ~eye:(1.,1.,1.) ~center:(0.,0.,0.) ~up:(0.,1.,0.);
    end;
    GlMat.mode `modelview;
    GlMat.load_identity ()

(*Le Main*)
let main () =
  let result3 = load_obj () in
  let _ = Glut.init Sys.argv in
    Glut.initWindowSize ~w:(fst !dim) ~h:(snd !dim);
    ignore (Glut.createWindow ~title:"Mapplestore 3D");
    Glut.reshapeFunc ~cb:reshape;
    Glut.displayFunc ~cb:(display result3);
    Glut.idleFunc ~cb:(Some idle);
    Glut.keyboardFunc ~cb:(fun ~key ~x ~y -> 
      if key=102 then fkey:=true;
      if key=114 then ekey:=true;);
    Glut.mainLoop()

let _ = main ()
